package cn.wp.user.service.impl;

import cn.wp.basic.constant.VerificationConstant;
import cn.wp.basic.exception.CustomException;
import cn.wp.basic.service.impl.BaseServiceImpl;
import cn.wp.basic.util.HttpClientUtils;
import cn.wp.user.constant.WechatConstant;
import cn.wp.user.domain.LoginInfo;
import cn.wp.user.domain.User;
import cn.wp.user.domain.WechatUser;
import cn.wp.user.dto.UserDto;
import cn.wp.user.mapper.LoginInfoMapper;
import cn.wp.user.mapper.UserMapper;
import cn.wp.user.mapper.WechatUserMapper;
import cn.wp.user.service.IWechatService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class WechatServiceImpl extends BaseServiceImpl<WechatUser> implements IWechatService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WechatUserMapper wechatUserMapper;

    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    private UserMapper userMapper;

    /**
     * 处理回调方法
     * @param map   授权码
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> handleCallBackMethod(Map<String, String> map) {
        // 获取授权码
        String code = map.get("code");
        // 获取token的url地址    appid账号 secret账号    code授权码
        String tokenUrl = WechatConstant.TOKEN_URL.replace("APPID", WechatConstant.APPID)
                .replace("SECRET", WechatConstant.SECRET)
                .replace("CODE", code);
        // 获取token的json字符串
        String tokenJsonStr = HttpClientUtils.httpGet(tokenUrl);
        // json字符串转换为json对象
        JSONObject jsonObject = JSON.parseObject(tokenJsonStr);

        // 获取openid（微信用户唯一标识）
        String openid = jsonObject.getString("openid");
        // 获取access_token值（接口调用凭证）
        String access_token = jsonObject.getString("access_token");
        System.out.println(openid + "    " + access_token);

        // 获取用户的url地址   openid（微信用户唯一标识）    access_token值（接口调用凭证）
        String userUrl = WechatConstant.USER_URL.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid);
        // 获取微信用户user的json字符串
        String userJsonStr = HttpClientUtils.httpGet(userUrl);
        // 转换为json对象
        jsonObject = JSON.parseObject(userJsonStr);
        System.out.println(jsonObject);

        // 根据openid查询微信用户对象
        WechatUser wechatUser = wechatUserMapper.loadByOpenid(openid);
        // 定义一个集合向门户网站响应后台数据
        Map<String, Object> resultMap = new HashMap<>();
        if (wechatUser == null){
            // 创建微信用户对象，保存数据
            wechatUser = new WechatUser();
            // openid
            wechatUser.setOpenid(openid);
            // 昵称
            wechatUser.setNickname(jsonObject.getString("nickname"));
            // 性别
            wechatUser.setSex(jsonObject.getInteger("sex"));
            // 地址
            wechatUser.setAddress(jsonObject.getString("country")
                    +jsonObject.getString("province")
                    +jsonObject.getString("city"));
            // 头像
            wechatUser.setHeadimgurl(jsonObject.getString("headimgurl"));
            // 保存微信用户
            wechatUserMapper.save(wechatUser);

            // 跳转到绑定页面，后端返回openid了就代表要跳转绑定页面
            resultMap.put("openid", openid);
            return resultMap;
        } else {
            // 获取loginfo 登录信息
            LoginInfo logininfo = wechatUser.getLogininfo();
            // 为空
            if (logininfo==null){
                // 跳转绑定页面
                resultMap.put("openid", openid);
                return resultMap;
            } else {
                // 否则有存在logininfo表示此微信已经绑定了手机号，直接登录
                // 生成token
                String token = UUID.randomUUID().toString();
                redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
                // 保存token和logininfo数据，给门户网站后台响应
                resultMap.put("token", token);
                resultMap.put("loginUser", logininfo);
                return resultMap;
            }
        }
    }

    /**
     * 微信绑定手机号
     * @param userDto
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> binder(UserDto userDto) throws CustomException {
        // 校验数据
        checkData(userDto);
        // 根据手机号和type查询t_logininfo中是否有对应的数据
        LoginInfo loginInfo = loginInfoMapper.loadByPhoneAndType(userDto.getPhone(), userDto.getType());

        // 如果不存在
        if (loginInfo == null){
            // 创建登录信息
            loginInfo = createLoginInfo(userDto);
            // 保存logininfo  有了id
            loginInfoMapper.save(loginInfo);
            // 创建用户
            User user = createUser(loginInfo);
            // 保存用户 包括logininfo_id
            userMapper.save(user);

            // 绑定微信
            wechatUserMapper.binderWechatAndLoginInfo(loginInfo.getId(),userDto.getOpenid());
        }else {
            // 绑定
            wechatUserMapper.binderWechatAndLoginInfo(loginInfo.getId(),userDto.getOpenid());
        }

        // 直接登录(给redis设置值，给浏览器存储token和loginUser)
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, loginInfo,30,TimeUnit.MINUTES);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("token", token);
        resultMap.put("loginUser", loginInfo);
        return resultMap;
    }

    // 创建用户
    private User createUser(LoginInfo loginInfo) {
        User user = new User();
        BeanUtils.copyProperties(loginInfo, user);
        user.setLoginInfo(loginInfo);
        return user;
    }

    // 创建登录信息
    private LoginInfo createLoginInfo(UserDto userDto) {
        LoginInfo loginInfo = new LoginInfo();
        // 设置手机号
        loginInfo.setPhone(userDto.getPhone());
        // 设置 type 0 后端管理用户 1 前端门户用户
        loginInfo.setType(userDto.getType());
        return loginInfo;
    }

    private void checkData(UserDto userDto) throws CustomException {
        if (StringUtils.isEmpty(userDto.getPhone())){
            throw new CustomException("手机号不能为空！");
        }
        if (StringUtils.isEmpty(userDto.getCode())){
            throw new CustomException("验证码不能为空！");
        }
        // redis中获取存储的验证码
        String codeValue = (String) redisTemplate.opsForValue().get(userDto.getPhone() + ":" + VerificationConstant.USER_BINDER);
        String code = codeValue.split(":")[0];
        if (!code.equals(userDto.getCode())){
            throw new CustomException("验证码错误！");
        }
    }

}
